home *** CD-ROM | disk | FTP | other *** search
/ Freelog 115 / FreelogNo115-MaiJuin2013.iso / Internet / AvantBrowser / asetup.exe / _data / webkit / resources.pak / Unnamed File 000076.txt < prev    next >
Text File  |  2013-04-03  |  12KB  |  380 lines

  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4.  
  5. /**
  6.  * @fileoverview This implements a table control.
  7.  */
  8.  
  9. cr.define('cr.ui', function() {
  10.   /** @const */ var ListSelectionModel = cr.ui.ListSelectionModel;
  11.   /** @const */ var ListSelectionController = cr.ui.ListSelectionController;
  12.   /** @const */ var ArrayDataModel = cr.ui.ArrayDataModel;
  13.   /** @const */ var TableColumnModel = cr.ui.table.TableColumnModel;
  14.   /** @const */ var TableList = cr.ui.table.TableList;
  15.   /** @const */ var TableHeader = cr.ui.table.TableHeader;
  16.  
  17.   /**
  18.    * Creates a new table element.
  19.    * @param {Object=} opt_propertyBag Optional properties.
  20.    * @constructor
  21.    * @extends {HTMLDivElement}
  22.    */
  23.   var Table = cr.ui.define('div');
  24.  
  25.   Table.prototype = {
  26.     __proto__: HTMLDivElement.prototype,
  27.  
  28.     columnModel_: new TableColumnModel([]),
  29.  
  30.     /**
  31.      * The table data model.
  32.      *
  33.      * @type {cr.ui.ArrayDataModel}
  34.      */
  35.     get dataModel() {
  36.       return this.list_.dataModel;
  37.     },
  38.     set dataModel(dataModel) {
  39.       if (this.list_.dataModel != dataModel) {
  40.         if (this.list_.dataModel) {
  41.           this.list_.dataModel.removeEventListener('sorted',
  42.                                                    this.boundHandleSorted_);
  43.           this.list_.dataModel.removeEventListener('change',
  44.                                                    this.boundHandleChangeList_);
  45.           this.list_.dataModel.removeEventListener('splice',
  46.                                                    this.boundHandleChangeList_);
  47.         }
  48.         this.list_.dataModel = dataModel;
  49.         if (this.list_.dataModel) {
  50.           this.list_.dataModel.addEventListener('sorted',
  51.                                                 this.boundHandleSorted_);
  52.           this.list_.dataModel.addEventListener('change',
  53.                                                 this.boundHandleChangeList_);
  54.           this.list_.dataModel.addEventListener('splice',
  55.                                                 this.boundHandleChangeList_);
  56.         }
  57.         this.header_.redraw();
  58.       }
  59.     },
  60.  
  61.     /**
  62.      * The list of table.
  63.      *
  64.      * @type {cr.ui.list}
  65.      */
  66.     get list() {
  67.       return this.list_;
  68.     },
  69.  
  70.     /**
  71.      * The table column model.
  72.      *
  73.      * @type {cr.ui.table.TableColumnModel}
  74.      */
  75.     get columnModel() {
  76.       return this.columnModel_;
  77.     },
  78.     set columnModel(columnModel) {
  79.       if (this.columnModel_ != columnModel) {
  80.         if (this.columnModel_)
  81.           this.columnModel_.removeEventListener('resize', this.boundResize_);
  82.         this.columnModel_ = columnModel;
  83.  
  84.         if (this.columnModel_)
  85.           this.columnModel_.addEventListener('resize', this.boundResize_);
  86.         this.list_.invalidate();
  87.         this.redraw();
  88.       }
  89.     },
  90.  
  91.     /**
  92.      * The table selection model.
  93.      *
  94.      * @type
  95.      * {cr.ui.ListSelectionModel|cr.ui.table.ListSingleSelectionModel}
  96.      */
  97.     get selectionModel() {
  98.       return this.list_.selectionModel;
  99.     },
  100.     set selectionModel(selectionModel) {
  101.       if (this.list_.selectionModel != selectionModel) {
  102.         if (this.dataModel)
  103.           selectionModel.adjustLength(this.dataModel.length);
  104.         this.list_.selectionModel = selectionModel;
  105.       }
  106.     },
  107.  
  108.     /**
  109.      * The accessor to "autoExpands" property of the list.
  110.      *
  111.      * @type {boolean}
  112.      */
  113.     get autoExpands() {
  114.       return this.list_.autoExpands;
  115.     },
  116.     set autoExpands(autoExpands) {
  117.       this.list_.autoExpands = autoExpands;
  118.     },
  119.  
  120.     get fixedHeight() {
  121.       return this.list_.fixedHeight;
  122.     },
  123.     set fixedHeight(fixedHeight) {
  124.       this.list_.fixedHeight = fixedHeight;
  125.     },
  126.  
  127.     /**
  128.      * Returns render function for row.
  129.      * @return {Function(*, cr.ui.Table): HTMLElement} Render function.
  130.      */
  131.     getRenderFunction: function() {
  132.       return this.list_.renderFunction_;
  133.     },
  134.  
  135.     /**
  136.      * Sets render function for row.
  137.      * @param {Function(*, cr.ui.Table): HTMLElement} Render function.
  138.      */
  139.     setRenderFunction: function(renderFunction) {
  140.       if (renderFunction === this.list_.renderFunction_)
  141.         return;
  142.  
  143.       this.list_.renderFunction_ = renderFunction;
  144.       cr.dispatchSimpleEvent(this, 'change');
  145.     },
  146.  
  147.     /**
  148.      * The header of the table.
  149.      *
  150.      * @type {cr.ui.table.TableColumnModel}
  151.      */
  152.     get header() {
  153.       return this.header_;
  154.     },
  155.  
  156.     /**
  157.      * Initializes the element.
  158.      */
  159.     decorate: function() {
  160.       this.header_ = this.ownerDocument.createElement('div');
  161.       this.list_ = this.ownerDocument.createElement('list');
  162.  
  163.       this.appendChild(this.header_);
  164.       this.appendChild(this.list_);
  165.  
  166.       TableList.decorate(this.list_);
  167.       this.list_.selectionModel = new ListSelectionModel(this);
  168.       this.list_.table = this;
  169.       this.list_.addEventListener('scroll', this.handleScroll_.bind(this));
  170.  
  171.       TableHeader.decorate(this.header_);
  172.       this.header_.table = this;
  173.  
  174.       this.classList.add('table');
  175.  
  176.       this.boundResize_ = this.resize.bind(this);
  177.       this.boundHandleSorted_ = this.handleSorted_.bind(this);
  178.       this.boundHandleChangeList_ = this.handleChangeList_.bind(this);
  179.  
  180.       // The contained list should be focusable, not the table itself.
  181.       if (this.hasAttribute('tabindex')) {
  182.         this.list_.setAttribute('tabindex', this.getAttribute('tabindex'));
  183.         this.removeAttribute('tabindex');
  184.       }
  185.  
  186.       this.addEventListener('focus', this.handleElementFocus_, true);
  187.       this.addEventListener('blur', this.handleElementBlur_, true);
  188.     },
  189.  
  190.     /**
  191.      * Redraws the table.
  192.      */
  193.     redraw: function(index) {
  194.       this.list_.redraw();
  195.       this.header_.redraw();
  196.     },
  197.  
  198.     startBatchUpdates: function() {
  199.       this.list_.startBatchUpdates();
  200.       this.header_.startBatchUpdates();
  201.     },
  202.  
  203.     endBatchUpdates: function() {
  204.       this.list_.endBatchUpdates();
  205.       this.header_.endBatchUpdates();
  206.     },
  207.  
  208.     /**
  209.      * Resize the table columns.
  210.      */
  211.     resize: function() {
  212.       // We resize columns only instead of full redraw.
  213.       this.list_.resize();
  214.       this.header_.resize();
  215.     },
  216.  
  217.     /**
  218.      * Ensures that a given index is inside the viewport.
  219.      * @param {number} index The index of the item to scroll into view.
  220.      * @return {boolean} Whether any scrolling was needed.
  221.      */
  222.     scrollIndexIntoView: function(i) {
  223.       this.list_.scrollIndexIntoView(i);
  224.     },
  225.  
  226.     /**
  227.      * Find the list item element at the given index.
  228.      * @param {number} index The index of the list item to get.
  229.      * @return {ListItem} The found list item or null if not found.
  230.      */
  231.     getListItemByIndex: function(index) {
  232.       return this.list_.getListItemByIndex(index);
  233.     },
  234.  
  235.     /**
  236.      * This handles data model 'sorted' event.
  237.      * After sorting we need to redraw header
  238.      * @param {Event} e The 'sorted' event.
  239.      */
  240.     handleSorted_: function(e) {
  241.       this.header_.redraw();
  242.     },
  243.  
  244.     /**
  245.      * This handles data model 'change' and 'splice' events.
  246.      * Since they may change the visibility of scrollbar, table may need to
  247.      * re-calculation the width of column headers.
  248.      * @param {Event} e The 'change' or 'splice' event.
  249.      */
  250.     handleChangeList_: function(e) {
  251.       webkitRequestAnimationFrame(this.header_.updateWidth.bind(this.header_));
  252.     },
  253.  
  254.     /**
  255.      * This handles list 'scroll' events. Scrolls the header accordingly.
  256.      * @param {Event} e Scroll event.
  257.      */
  258.     handleScroll_: function(e) {
  259.       this.header_.style.marginLeft = -this.list_.scrollLeft + 'px';
  260.     },
  261.  
  262.     /**
  263.      * Sort data by the given column.
  264.      * @param {number} index The index of the column to sort by.
  265.      */
  266.     sort: function(i) {
  267.       var cm = this.columnModel_;
  268.       var sortStatus = this.list_.dataModel.sortStatus;
  269.       if (sortStatus.field == cm.getId(i)) {
  270.         var sortDirection = sortStatus.direction == 'desc' ? 'asc' : 'desc';
  271.         this.list_.dataModel.sort(sortStatus.field, sortDirection);
  272.       } else {
  273.         this.list_.dataModel.sort(cm.getId(i), cm.getDefaultOrder(i));
  274.       }
  275.       if (this.selectionModel.selectedIndex == -1)
  276.         this.list_.scrollTop = 0;
  277.     },
  278.  
  279.     /**
  280.      * Called when an element in the table is focused. Marks the table as having
  281.      * a focused element, and dispatches an event if it didn't have focus.
  282.      * @param {Event} e The focus event.
  283.      * @private
  284.      */
  285.     handleElementFocus_: function(e) {
  286.       if (!this.hasElementFocus) {
  287.         this.hasElementFocus = true;
  288.         // Force styles based on hasElementFocus to take effect.
  289.         this.list_.redraw();
  290.       }
  291.     },
  292.  
  293.     /**
  294.      * Called when an element in the table is blurred. If focus moves outside
  295.      * the table, marks the table as no longer having focus and dispatches an
  296.      * event.
  297.      * @param {Event} e The blur event.
  298.      * @private
  299.      */
  300.     handleElementBlur_: function(e) {
  301.       // When the blur event happens we do not know who is getting focus so we
  302.       // delay this a bit until we know if the new focus node is outside the
  303.       // table.
  304.       var table = this;
  305.       var list = this.list_;
  306.       var doc = e.target.ownerDocument;
  307.       window.setTimeout(function() {
  308.         var activeElement = doc.activeElement;
  309.         if (!table.contains(activeElement)) {
  310.           table.hasElementFocus = false;
  311.           // Force styles based on hasElementFocus to take effect.
  312.           list.redraw();
  313.         }
  314.       });
  315.     },
  316.  
  317.     /**
  318.      * Adjust column width to fit its content.
  319.      * @param {number} index Index of the column to adjust width.
  320.      */
  321.     fitColumn: function(index) {
  322.       var list = this.list_;
  323.       var listHeight = list.clientHeight;
  324.  
  325.       var cm = this.columnModel_;
  326.       var dm = this.dataModel;
  327.       var columnId = cm.getId(index);
  328.       var doc = this.ownerDocument;
  329.       var render = cm.getRenderFunction(index);
  330.       var table = this;
  331.       var MAXIMUM_ROWS_TO_MEASURE = 1000;
  332.  
  333.       // Create a temporaty list item, put all cells into it and measure its
  334.       // width. Then remove the item. It fits "list > *" CSS rules.
  335.       var container = doc.createElement('li');
  336.       container.style.display = 'inline-block';
  337.       container.style.textAlign = 'start';
  338.       // The container will have width of the longest cell.
  339.       container.style.webkitBoxOrient = 'vertical';
  340.  
  341.       // Ensure all needed data available.
  342.       dm.prepareSort(columnId, function() {
  343.         // Select at most MAXIMUM_ROWS_TO_MEASURE items around visible area.
  344.         var items = list.getItemsInViewPort(list.scrollTop, listHeight);
  345.         var firstIndex = Math.floor(Math.max(0,
  346.             (items.last + items.first - MAXIMUM_ROWS_TO_MEASURE) / 2));
  347.         var lastIndex = Math.min(dm.length,
  348.                                  firstIndex + MAXIMUM_ROWS_TO_MEASURE);
  349.         for (var i = firstIndex; i < lastIndex; i++) {
  350.           var item = dm.item(i);
  351.           var div = doc.createElement('div');
  352.           div.className = 'table-row-cell';
  353.           div.appendChild(render(item, columnId, table));
  354.           container.appendChild(div);
  355.         }
  356.         list.appendChild(container);
  357.         var width = parseFloat(getComputedStyle(container).width);
  358.         list.removeChild(container);
  359.         cm.setWidth(index, width);
  360.       });
  361.     },
  362.  
  363.     normalizeColumns: function() {
  364.       this.columnModel.normalizeWidths(this.clientWidth);
  365.     }
  366.   };
  367.  
  368.   /**
  369.    * Whether the table or one of its descendents has focus. This is necessary
  370.    * because table contents can contain controls that can be focused, and for
  371.    * some purposes (e.g., styling), the table can still be conceptually focused
  372.    * at that point even though it doesn't actually have the page focus.
  373.    */
  374.   cr.defineProperty(Table, 'hasElementFocus', cr.PropertyKind.BOOL_ATTR);
  375.  
  376.   return {
  377.     Table: Table
  378.   };
  379. });
  380.